package com.example.aimultimodel.tools;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 高性能文件操作工具类 - 优化版
 * 优化点：
 * 1. 使用Java流式处理减少内存占用
 * 2. 采用NIO.2 API提高I/O性能
 * 3. 减少对象创建和内部类使用
 * 4. 合并重复逻辑减少代码量
 * @author 18747
 */
@Component
public class FileOperationTool {

    // 最大读取/写入文件大小（10MB）
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024;
    private static final int BATCH_SIZE = 3;
    private static final Set<String> SUPPORTED_EXTENSIONS = Set.of(
            "txt", "java", "xml", "json", "md", "html", "css", "js",
            "properties", "vue", "ts", "jsx", "tsx", "yaml", "yml", "sql"
    );
    private static final Set<String> RESTRICTED_PATHS = Set.of(
            "/", "C:\\", "/etc", "/bin", "/usr", "/windows", "/system32"
    );

    @Tool(description = "分页读取文件夹内容，参数1为文件夹路径，参数2为页码（从0开始，可选，默认为0）")
    public String readFolder(String folderPath, Integer page) {
        try {
            int currentPage = page != null ? page : 0;
            if (currentPage < 0) return "❌ 页码必须大于等于0";

            Path rootPath = Paths.get(folderPath).toAbsolutePath().normalize();
            if (!Files.exists(rootPath) || !Files.isDirectory(rootPath)) {
                return "❌ 无效的文件夹路径：" + folderPath;
            }
            if (isRestrictedDirectory(rootPath)) {
                return "❌ 出于安全考虑，无法读取该目录";
            }

            // 使用流式处理减少内存占用
            try (Stream<Path> fileStream = Files.walk(rootPath, Integer.MAX_VALUE)) {
                List<Path> files = fileStream
                        .filter(Files::isRegularFile)
                        .filter(this::isSupportedFile)
                        .sorted(Comparator.comparing(p -> p.getFileName().toString()))
                        .collect(Collectors.toList());

                int totalFiles = files.size();
                int totalPages = (int) Math.ceil((double) totalFiles / BATCH_SIZE);

                if (files.isEmpty()) {
                    return "📁 文件夹中没有支持的文件类型。支持的类型：" + String.join(", ", SUPPORTED_EXTENSIONS);
                }
                if (currentPage >= totalPages) {
                    return "📄 页码超出范围，总页数：" + totalPages + "，有效页码：0-" + (totalPages - 1);
                }

                int start = currentPage * BATCH_SIZE;
                int end = Math.min(start + BATCH_SIZE, totalFiles);

                // 使用预分配容量的StringBuilder提高性能
                StringBuilder result = new StringBuilder(1024);
                result.append("📁 文件夹: ").append(folderPath).append("\n")
                        .append("📊 统计: 第 ").append(currentPage + 1).append("/").append(totalPages)
                        .append(" 页，文件 ").append(start + 1).append("-").append(end)
                        .append("（总共 ").append(totalFiles).append(" 个文件）\n\n");

                for (int i = start; i < end; i++) {
                    Path file = files.get(i);
                    result.append("--- 文件 ").append(i + 1).append(" ---\n")
                            .append("📝 路径: ").append(file).append("\n")
                            .append("📄 名称: ").append(file.getFileName()).append("\n")
                            .append("📏 大小: ").append(formatFileSize(Files.size(file))).append("\n")
                            .append("内容:\n").append(readFileContentSafely(file)).append("\n\n");
                }

                return addPaginationNavigation(result, folderPath, currentPage, totalPages);
            }
        } catch (Exception e) {
            return "❌ 读取文件夹时发生错误：" + e.getMessage();
        }
    }

    @Tool(description = "读取单个文件的内容。参数为文件完整路径。")
    public String readFile(String filePath) {
        try {
            Path path = Paths.get(filePath).toAbsolutePath().normalize();
            if (!Files.exists(path) || !Files.isRegularFile(path)) {
                return "❌ 文件不存在或不是文件：" + filePath;
            }
            if (isRestrictedDirectory(path.getParent())) {
                return "❌ 出于安全考虑，无法读取该文件";
            }
            if (!isSupportedFile(path)) {
                return "❌ 不支持的文件类型，支持的类型：" + String.join(", ", SUPPORTED_EXTENSIONS);
            }

            return "📄 文件路径: " + path + "\n" +
                    "📏 文件大小: " + formatFileSize(Files.size(path)) + "\n" +
                    "内容:\n" + readFileContentSafely(path);
        } catch (Exception e) {
            return "❌ 读取文件时发生错误：" + e.getMessage();
        }
    }

    @Tool(description = "创建新文件，参数1为文件完整路径，参数2为初始内容（可选，为空则创建空文件）。")
    public String createFile(String filePath, String content) {
        try {
            Path path = Paths.get(filePath).toAbsolutePath().normalize();
            if (isRestrictedDirectory(path.getParent())) {
                return "❌ 出于安全考虑，无法在该位置创建文件";
            }
            if (Files.exists(path)) {
                return "❌ 文件已存在：" + filePath;
            }

            // 创建父目录（如果不存在）
            if (path.getParent() != null) {
                Files.createDirectories(path.getParent());
            }

            // 使用NIO.2 API高效写入
            if (content != null && !content.isEmpty()) {
                Files.writeString(path, content, StandardCharsets.UTF_8);
            } else {
                Files.createFile(path);
            }
            return "✅ 文件创建成功：" + filePath;
        } catch (Exception e) {
            return "❌ 创建文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "修改文件内容（覆盖原有内容），参数1为文件完整路径，参数2为新内容。")
    public String modifyFile(String filePath, String newContent) {
        try {
            Path path = Paths.get(filePath).toAbsolutePath().normalize();
            if (!Files.exists(path) || !Files.isRegularFile(path)) {
                return "❌ 文件不存在或不是文件：" + filePath;
            }
            if (isRestrictedDirectory(path.getParent())) {
                return "❌ 出于安全考虑，无法修改该文件";
            }
            if (!isSupportedFile(path)) {
                return "❌ 不支持修改此类型文件，支持的类型：" + String.join(", ", SUPPORTED_EXTENSIONS);
            }
            if (newContent.getBytes(StandardCharsets.UTF_8).length > MAX_FILE_SIZE) {
                return "❌ 修改失败：内容超过10MB限制";
            }

            Files.writeString(path, newContent, StandardCharsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING);
            return "✅ 文件内容修改成功：" + filePath;
        } catch (Exception e) {
            return "❌ 修改文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "删除文件，参数为文件完整路径。")
    public String deleteFile(String filePath) {
        try {
            Path path = Paths.get(filePath).toAbsolutePath().normalize();
            if (!Files.exists(path)) {
                return "ℹ️ 文件不存在：" + filePath;
            }
            if (!Files.isRegularFile(path)) {
                return "❌ 指定路径不是文件：" + filePath;
            }
            if (isRestrictedDirectory(path.getParent())) {
                return "❌ 出于安全考虑，无法删除该文件";
            }
            if (isImportantFile(path)) {
                return "❌ 出于安全考虑，无法删除该文件（可能是重要系统文件）";
            }

            Files.delete(path);
            return "✅ 文件删除成功：" + filePath;
        } catch (Exception e) {
            return "❌ 删除文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "删除文件夹及其所有内容，参数为文件夹完整路径。")
    public String deleteFolder(String folderPath) {
        try {
            Path path = Paths.get(folderPath).toAbsolutePath().normalize();
            if (!Files.exists(path) || !Files.isDirectory(path)) {
                return "❌ 无效的文件夹路径：" + folderPath;
            }
            if (isRestrictedDirectory(path)) {
                return "❌ 出于安全考虑，无法删除该文件夹";
            }

            // 使用流式计算文件夹大小和文件数量
            try (Stream<Path> stream = Files.walk(path)) {
                long totalSize = stream.filter(Files::isRegularFile).mapToLong(p -> {
                    try { return Files.size(p); } catch (IOException e) { return 0; }
                }).sum();

                long fileCount = Files.walk(path)
                        .filter(Files::isRegularFile)
                        .count();

                if (fileCount > 100) {
                    return "❌ 文件夹包含文件过多（" + fileCount + " 个文件），请手动确认后删除";
                }

                // 递归删除文件和目录
                Files.walk(path)
                        .sorted(Comparator.reverseOrder())
                        .forEach(p -> { try { Files.delete(p); } catch (IOException e) { /* 忽略 */ } });

                return "✅ 文件夹删除成功：" + folderPath + "\n" +
                        "删除统计: " + fileCount + " 个文件，总大小 " + formatFileSize(totalSize);
            }
        } catch (Exception e) {
            return "❌ 删除文件夹失败：" + e.getMessage();
        }
    }

    @Tool(description = "列出文件夹中的文件和子文件夹（不读取内容），参数为文件夹完整路径。")
    public String listFolder(String folderPath) {
        try {
            Path path = Paths.get(folderPath).toAbsolutePath().normalize();
            if (!Files.exists(path) || !Files.isDirectory(path)) {
                return "❌ 无效的文件夹路径：" + folderPath;
            }
            if (isRestrictedDirectory(path)) {
                return "❌ 出于安全考虑，无法访问该目录";
            }

            // 使用NIO.2的list方法提高性能
            try (Stream<Path> stream = Files.list(path)) {
                StringBuilder result = new StringBuilder(512);
                result.append("📁 文件夹内容: ").append(folderPath).append("\n\n");

                stream.sorted(Comparator.comparing(p -> p.getFileName().toString()))
                        .forEach(p -> {
                            if (Files.isDirectory(p)) {
                                result.append("📁 ").append(p.getFileName()).append("/\n");
                            } else {
                                try {
                                    result.append("📄 ").append(p.getFileName())
                                            .append(" (").append(formatFileSize(Files.size(p))).append(")\n");
                                } catch (IOException e) {
                                    result.append("📄 ").append(p.getFileName()).append(" (大小未知)\n");
                                }
                            }
                        });
                return result.toString();
            }
        } catch (Exception e) {
            return "❌ 列出文件夹内容时发生错误：" + e.getMessage();
        }
    }

    // ========== 辅助方法 ==========

    private String readFileContentSafely(Path path) {
        try {
            long size = Files.size(path);
            if (size > MAX_FILE_SIZE) {
                return "❌ 文件过大（超过10MB限制），无法读取完整内容。";
            }
            return Files.readString(path, StandardCharsets.UTF_8);
        } catch (IOException e) {
            return "❌ 读取失败: " + e.getMessage();
        }
    }

    private boolean isSupportedFile(Path file) {
        try {
            String fileName = file.getFileName().toString().toLowerCase();
            int dotIndex = fileName.lastIndexOf('.');
            String extension = (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
            return SUPPORTED_EXTENSIONS.contains(extension);
        } catch (Exception e) {
            return false;
        }
    }

    private String formatFileSize(long size) {
        if (size < 1024) return size + " B";
        if (size < 1024 * 1024) return String.format("%.1f KB", size / 1024.0);
        return String.format("%.1f MB", size / (1024.0 * 1024.0));
    }

    private boolean isRestrictedDirectory(Path path) {
        if (path == null) return false;
        String absolutePath = path.toString();
        return RESTRICTED_PATHS.stream().anyMatch(restricted ->
                absolutePath.startsWith(restricted) || absolutePath.equals(restricted));
    }

    private boolean isImportantFile(Path path) {
        String fileName = path.getFileName().toString().toLowerCase();
        return Set.of(
                "boot.ini", "ntldr", "ntdetect.com", "io.sys", "msdos.sys",
                "config.sys", "autoexec.bat", "windows", "system32", "etc", "bin"
        ).contains(fileName);
    }

    private String addPaginationNavigation(StringBuilder result, String folderPath, int currentPage, int totalPages) {
        if (currentPage > 0) {
            result.append("• 上一页: readFolder('").append(folderPath).append("', ").append(currentPage - 1).append(")\n");
        }
        if (currentPage < totalPages - 1) {
            result.append("• 下一页: readFolder('").append(folderPath).append("', ").append(currentPage + 1).append(")\n");
        }
        if (totalPages > 1) {
            result.append("• 跳转页面: 修改 page 参数 (0-").append(totalPages - 1).append(")\n");
        }
        return result.toString();
    }
}
